home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / internet / javnl005.zip / JAVNL005.TXT < prev   
Text File  |  1996-05-14  |  16KB  |  510 lines

  1. Issue #005
  2. May, 1996
  3.  
  4.  
  5. Contents:
  6.  
  7. Comparing C/C++ with Java Part 5 - Multiple Inheritance
  8. Sorting in Java
  9. Java Program Packaging Part 3 - Protected/Default
  10. Performance - Method Call Overhead
  11.  
  12.  
  13. COMPARING C/C++ WITH JAVA PART 5 - MULTIPLE INHERITANCE
  14.  
  15. Suppose that you have two C++ classes:
  16.  
  17.         class A {
  18.         public:
  19.                 int x;
  20.                 void f();
  21.         };
  22.  
  23.         class B {
  24.         public:
  25.                 int y;
  26.                 void g();
  27.         };
  28.  
  29. and a third class that derives or inherits ("extends") from both of
  30. these:
  31.  
  32.         class C : public A, public B {
  33.                 // stuff
  34.         };
  35.  
  36. Inheriting from multiple base classes is called "multiple inheritance"
  37. or MI for short.
  38.  
  39. Like templates that we discussed in issue #004, multiple inheritance
  40. adds to the complexity of C++, while offering a solution to some
  41. particular kinds of programming problems.  One type of issue with
  42. programming using MI is in deciding which of a set of conflicting
  43. inherited names "wins".
  44.  
  45. Java does not have multiple inheritance.  It does, however, have a way
  46. of doing some of what MI is intended for, relative to inheriting
  47. attributes.  In Java there is a language feature called an interface,
  48. which looks like this:
  49.  
  50.         public interface Orderable {
  51.                 // return < 0 if p1 < p2, 0 if equal, > 0 if p1 > p2
  52.                 public int compareTo(Object p1, Object p2);
  53.         }
  54.  
  55. This looks somewhat like a class, except that all the methods are
  56. abstract, that is, are not implemented immediately but serve as
  57. placeholders.
  58.  
  59. What is an interface used for?  Suppose that you want to ensure that a
  60. particular class has certain properties, in the present case that it
  61. defines the method compareTo() to order objects.  You can enforce this
  62. by requiring that the class implement interface Orderable:
  63.  
  64.         public class xxx implements Orderable {
  65.                 public int compareTo(Object p1, Object p2)
  66.                 {
  67.                         int n1 = ((Integer)p1).intValue();
  68.                         int n2 = ((Integer)p2).intValue();
  69.                         return n1 - n2;
  70.                 }
  71.         }
  72.  
  73. Why do we care about this?  In the next section we will talk about
  74. sorting in Java.  To write a semi-general sort method, it's necessary
  75. to assume that the objects within a Vector of objects to be sorted
  76. have some ordering method available to rank them.  Java by default has
  77. no way of ordering two arbitrary objects.
  78.  
  79. By defining an Orderable interface, and either sorting a vector of
  80. Orderables (that is, a vector of object types where the type is
  81. defined to implement Orderable), or sorting a Vector of Objects with a
  82. compareTo() method passed to the sort routine via a method wrapper
  83. (see next section), we can ensure that a compareTo() method is
  84. available.
  85.  
  86. An interface is sort of like a base class for a class.  If you have
  87. an Orderable reference:
  88.  
  89.         Orderable or = null;
  90.  
  91. it's possible to assign to it a reference to an object type that
  92. implements Orderable:
  93.  
  94.         xxx x = new xxx();
  95.  
  96.         or = x;
  97.  
  98. Again, if we have an Orderable object reference, we can be sure that a
  99. method call like:
  100.  
  101.         or.compareTo(p1, p2)
  102.  
  103. will be valid.
  104.  
  105.  
  106. SORTING IN JAVA
  107.  
  108. In the last issue we talked about sorting in Java and said that
  109. there's no approach to sorting that's really similar to qsort() in
  110. C/C++.  A couple of people wrote to me about this and suggested a
  111. technique that does in fact have some similarities.
  112.  
  113. The idea is to write a sort method that accepts a Vector of Object
  114. references, along with a class object instance that is a wrapper for a
  115. compareTo() method as illustrated above.  The sort routine will
  116. iterate over the vector and call out to the compare method to
  117. determine the ordering of any two objects.  Specifically, this would
  118. look like:
  119.  
  120.         import java.util.Vector;
  121.         
  122.         // Orderable interface
  123.         
  124.         interface Orderable {
  125.                 // return < 0 if p1 < p2, 0 if equal, > 0 if p1 > p2
  126.                 public int compareTo(Object p1, Object p2);
  127.         };
  128.         
  129.         // wrapper for a compareTo() method for ordering Strings
  130.         
  131.         class Ord implements Orderable {
  132.                 public int compareTo(Object p1, Object p2)
  133.                 {
  134.                         return ((String)p1).compareTo(((String)p2));
  135.                 }
  136.         }
  137.         
  138.         public class Sort {
  139.         
  140.                 public static void sort(Vector v, Orderable or)
  141.                 {
  142.                         if (v == null || or == null)
  143.                                 ; // give error of some kind
  144.         
  145.                         // get vector size
  146.         
  147.                         int n = v.size();
  148.         
  149.                         // sort
  150.         
  151.                         for (int i = 0; i < n - 1; i++) {
  152.                                 for (int j = i + 1; j < n; j++) {
  153.         
  154.                                         // do comparison
  155.         
  156.                                         if (or.compareTo(v.elementAt(i),
  157.                                             v.elementAt(j)) > 0) {
  158.                                                 Object ti = v.elementAt(i);
  159.                                                 Object tj = v.elementAt(j);
  160.                                                 v.setElementAt(tj, i);
  161.                                                 v.setElementAt(ti, j);
  162.                                         }
  163.                                 }
  164.                         }
  165.                 }
  166.         
  167.                 // driver program
  168.         
  169.                 public static void main(String args[])
  170.                 {
  171.                         Vector v = new Vector();
  172.                         int N = 100;
  173.                         int i = 0;
  174.         
  175.                         // add some strings
  176.         
  177.                         for (i = 0; i < N; i++)
  178.                                 v.addElement("xxx" + i);
  179.         
  180.                         // sort them
  181.         
  182.                         Sort.sort(v, new Ord());
  183.         
  184.                         // display the sorted list
  185.         
  186.                         for (i = 0; i < N; i++)
  187.                                 System.out.println((String)v.elementAt(i));
  188.                 }
  189.         
  190.         }
  191.  
  192. This code can be tuned in various ways (starting with the sort
  193. algorithm) but is illustrative of the technique.  We can implement any
  194. sort strategy we want on a Vector of objects simply by changing the
  195. ordering method.  For example, saying:
  196.  
  197.         class Ordrev implements Orderable {
  198.                 public int compareTo(Object p1, Object p2)
  199.                 {
  200.                         return -((String)p1).compareTo(((String)p2));
  201.                 }
  202.         }
  203.  
  204.         ...
  205.  
  206.         Sort.sort(v, new Ordrev());
  207.  
  208. will reverse the sorting order for Strings.  In this particular
  209. example, Strings have a compareTo() method already defined, and we
  210. simply cast the Object references to Strings and call this method.
  211. Note that if the wrong compareTo() wrapper instance is used, then an
  212. illegal cast will be attempted, resulting in an exception being
  213. thrown.  For example, the above case expects a String, and will
  214. generate an exception ("ClassCastException") if the objects we pass in
  215. are actually Integers.  The "instanceof" operator can be used to help
  216. sort things out.
  217.  
  218. In production code we'd have Orderable defined in a separate source
  219. file.  Ord might or might not be in its own file, depending on
  220. stylistic preferences.  Ord is simply a wrapper for a particular
  221. compareTo() method.  In C or C++ we would pass in a function pointer
  222. directly, but Java has no user-visible pointers and no global
  223. functions.
  224.  
  225. If we critique this approach and compare it to qsort(), there are some
  226. notable differences and some similarities:
  227.  
  228.         1.  This approach is higher-level than qsort(), because it
  229.         doesn't fool with pointers and sizes of objects and so on.
  230.  
  231.         2.  This approach cannot be used to directly sort vectors of
  232.         fundamental data types like int or double.  They must be
  233.         sorted using object wrappers.
  234.  
  235.         3.  Both approaches require calling out to a function or
  236.         method that is used to order elements.  Such calls are
  237.         expensive.
  238.  
  239.         4.  This approach has some overhead in accessing and setting
  240.         Vector element slots.  There is method call overhead, as well
  241.         as the subscript range checking done each time within a method
  242.         like elementAt().
  243.  
  244. It's possible to write a similar type of method for doing binary
  245. searches, kind of like bsearch() in the C library.
  246.  
  247.  
  248. JAVA PROGRAM PACKAGING PART 3 - PROTECTED/DEFAULT
  249.  
  250. In issue #004 we talked about public and private fields.  When public
  251. is applied to a method or variable:
  252.  
  253.         public int x = 37;
  254.  
  255.         public void f() {}
  256.  
  257. it means that the method or variable is visible everywhere, while a
  258. private method or variable:
  259.  
  260.         private int x = 37;
  261.  
  262.         private void f() {}
  263.  
  264. is visible only within the class where it is defined.
  265.  
  266. Two other levels of visibility are protected:
  267.  
  268.         protected int x = 37;
  269.  
  270. and the default when no keyword is specified:
  271.  
  272.         void f() {}
  273.  
  274. These are identical except in one case.  For both of these levels, the
  275. method or variable is visible in the class where it's defined and to
  276. subclasses and non-subclasses from the same package.  For example:
  277.  
  278.         // file pack1/A.java
  279.  
  280.         package pack1;
  281.  
  282.         public class A {
  283.                 protected int x = 0;
  284.                 int f() {return x;}
  285.                 public static void main(String args[]) {}
  286.         }
  287.  
  288.         class B extends A {
  289.                 void g()
  290.                 {
  291.                         A p = new A();
  292.                         int i = p.x + p.f();
  293.                 }
  294.         }
  295.  
  296.         class C {
  297.                 void g()
  298.                 {
  299.                         A p = new A();
  300.                         int i = p.x + p.f();
  301.                 }       
  302.         }
  303.  
  304. while not being accessible from other packages:
  305.  
  306.         // file pack1/AA.java
  307.  
  308.         package pack1;
  309.  
  310.         public class AA {
  311.                 protected int x = 0;
  312.                 int f() {return x;}
  313.                 public static void main(String args[]) {}
  314.         }
  315.  
  316.         // file pack2/BB.java
  317.  
  318.         package pack2;
  319.  
  320.         import pack1.AA;
  321.  
  322.         class BB extends AA {
  323.                 void g()
  324.                 {
  325.                         AA p = new AA();
  326.                         int i = p.x + p.f(); // error here
  327.                 }
  328.         }
  329.  
  330.         class CC {
  331.                 void g()
  332.                 {
  333.                         AA p = new AA();
  334.                         int i = p.x + p.f(); // error here
  335.                 }       
  336.         }
  337.  
  338. Where protected and the default differ is in whether they are
  339. inherited by a subclass in a different package.  For example:
  340.  
  341.         // file pack1/D.java
  342.  
  343.         package pack1;
  344.  
  345.         public class D {
  346.                 int x = 37;
  347.                 protected int y = 47;
  348.                 public static void main(String args[]) {}
  349.         }
  350.  
  351.         // file pack2/E.java
  352.  
  353.         package pack2;
  354.  
  355.         import pack1.D;
  356.  
  357.         class E extends D {
  358.                 void f()
  359.                 {
  360.                         int i = x;              // error here
  361.                         int j = y;              // OK here
  362.                 }
  363.         }
  364.  
  365. There are a couple more issues with packaging that we will explore in
  366. future issues.
  367.  
  368.  
  369. PERFORMANCE - METHOD CALL OVERHEAD
  370.  
  371. In a language such as C or C++ you may have encountered the idea that
  372. calling a function ("method" in Java) has some time overhead
  373. associated with it beyond the actual processing done by the function.
  374. For example, with this code:
  375.  
  376.         int max(int a, int b)
  377.         {
  378.                 return (a > b ? a : b);
  379.         }
  380.  
  381.         int main()
  382.         {
  383.                 int i = 0;
  384.                 int j = 0;
  385.                 int k = 0;
  386.                 long n = 50000000L;
  387.                 while (n-- > 0)
  388.                         //k = max(i, j);
  389.                         k = (i > j ? i : j);
  390.  
  391.                 return 0;
  392.         }
  393.  
  394. coding the actual calculation of the maximum of two ints is about
  395. three times as fast when done inline as when done via a call to
  396. max().  In C++ there is an "inline" specifier that can be used to
  397. specify that a function should be expanded inline if possible.
  398.  
  399. Function call overhead is caused by various factors, including time
  400. spent in setting up stack frames, actual transfer of control to the
  401. called function, and so on.
  402.  
  403. Java also has overhead with calling methods.  For example, in this
  404. code:
  405.  
  406.         public class xx {
  407.  
  408.                 public /*final*/ int max(int a, int b)
  409.                 {
  410.                         return (a > b ? a : b);
  411.                 }
  412.  
  413.                 public static void main(String args[])
  414.                 {
  415.                         int i = 0;
  416.                         int j = 0;
  417.                         int k = 0;
  418.                         int n = 1000000;
  419.                         xx p = new xx();
  420.  
  421.                         while (n-- > 0)
  422.                                 //k = p.max(i, j);
  423.                                 k = (i > j ? i : j);
  424.                 }
  425.  
  426.         }
  427.  
  428. doing the max computation inline is about twice as fast as calling the
  429. method max().
  430.  
  431. In Java one reason for overhead is that methods are virtual by
  432. default, that is, the actual method that is called is determined at
  433. run time by considering the actual object type.  For example, the
  434. Object class, from which all other class types derive, has a method
  435. hashCode() defined in it.  A class that extends from Object may also
  436. have a hashCode() method.  If in a program you have an Object
  437. reference, and wish to call hashCode():
  438.  
  439.         public void f(Object p)
  440.         {
  441.                 int h = p.hashCode();
  442.         }
  443.  
  444. then the actual version of hashCode() that is called depends on
  445. whether p is "really" an Object or refers to an instance of a class
  446. derived from Object.
  447.  
  448. So, because a method is virtual by default, it is difficult or
  449. impossible to expand it as inline (in C++ there have been some clever
  450. optimizations that have been used to make virtual functions inline,
  451. but this is a hard problem).
  452.  
  453. The keyword "final" can be used to say "this method cannot be
  454. overridden" by another method in a derived class.  With JDK 1.0 this
  455. optimization has no effect, but over the long term specifying "final"
  456. is likely to be an important optimization.  Note that "final" has
  457. various other meanings, for example saying:
  458.  
  459.         final int N = 10;
  460.  
  461. marks N as unchangeable, and a final class cannot be extended from.
  462.  
  463. Should you worry about method call overhead?  Most of the time, no.
  464. It's only when you have a method that's called very heavily in a loop
  465. that this overhead matters.
  466.  
  467.  
  468. ACKNOWLEDGEMENTS
  469.  
  470. Thanks to Thierry Ciot, Irv Kanode, Mike Paluka, and Alan Saldanha for
  471. help with proofreading.
  472.  
  473.  
  474. SUBSCRIPTION INFORMATION / BACK ISSUES
  475.  
  476. To subscribe to the newsletter, send mail to majordomo@world.std.com
  477. with this line as its message body:
  478.  
  479. subscribe java_letter
  480.  
  481. Back issues are available via FTP from:
  482.  
  483.         rmii.com /pub2/glenm/javalett
  484.  
  485. or on the Web at:
  486.  
  487.         http://www.rmii.com/~glenm
  488.  
  489. There is also a C++ newsletter.  To subscribe to it, say:
  490.  
  491. subscribe c_plus_plus
  492.  
  493. using the same majordomo@world.std.com address.
  494.  
  495. -------------------------
  496.  
  497. Copyright (c) 1996 Glen McCluskey.  All Rights Reserved.
  498.  
  499. This newsletter may be further distributed provided that it is copied
  500. in its entirety, including the newsletter number at the top and the
  501. copyright and contact information at the bottom.
  502.  
  503. Glen McCluskey & Associates
  504. Professional Computer Consulting
  505. Internet: glenm@glenmccl.com
  506. Phone: (800) 722-1613 or (970) 490-2462
  507. Fax: (970) 490-2463
  508. FTP: rmii.com /pub2/glenm/javalett (for back issues)
  509. Web: http://www.rmii.com/~glenm
  510.